
export class GameNetMgr{
    dataEventHandler: cc.Node;
    roomId;
    /**最多多少局 */
    maxNumOfGames = 0;
    /**当前第几局 */
    numOfGames = 0;
    /**剩余多少张牌 */
    numOfMJ = 0;
    seatIndex = -1;
    seats: cc.seat[];
    /**第几回合 */
    get turn(){
        return this._turn;
    }

    set turn(value){
        if(value !== this._turn){
            this._turn = value;
        }
        if(this.isAutomatic){
            cc.find('Canvas').getComponent('MJGame').autoChuPai();
        }
    }
    _turn = -1;

    
    button = -1;
    dingQue = -1;
    chuPai = -1;
    isDingQueing = false;
    isHuanSanZhang = false;

    /**当前需要操作的数据(碰、杠等) */
    curAction:cc.curAction = null;

    huanPaiMethod = -1;

    gamestate: '' | 'begin' | 'playing' | 'dingque' | 'huanpai' = '';
    isOver = false;
    conf:cc.conf;

    /**解散房间的消息集合 */
    dissolveData = null;

    /**定缺是否已经全部完成 */
    isDingQueFinished = false;

    /**是否自动托管状态 */
    isAutomatic = false;
    

    /**初始化监听各种事件 */
    initHandlers(){
        // 监听-》获取创建房间的信息
        cc.vv.net.addHandler(cc.vv.game_event_map.LOGIN_RESULT, data => {
            console.log(data);

            if(data.errcode === 0){
                var data_data = data.data;
                this.roomId = data_data.roomId;
                this.conf = data_data.conf;
                this.maxNumOfGames = data_data.conf.maxGames;
                this.numOfGames = data_data.numOfGames;
                this.seats = data_data.seats;
                this.seatIndex = this.getSeatIndexById(cc.vv.userMgr.userId);
                this.isOver = false;
            }
            else{
                console.log(data.errmsg);
            }
            this.dispatchEvent(cc.vv.game_event_map.LOGIN_RESULT);
        });

        // 监听-》通知其他玩家后进入打牌界面
        cc.vv.net.addHandler(cc.vv.game_event_map.LOGIN_FINISHED, (data) => {
            console.log('%clogin_finished', cc.vv.logStyle);
            cc.director.loadScene('mjgame', () => {
                cc.vv.net.ping();
                cc.vv.wc.hide();
            });
            this.dispatchEvent(cc.vv.game_event_map.LOGIN_FINISHED);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.EXIT_RESULT, () => {
            this.roomId = null;
            this.turn = -1;
            this.dingQue = -1;
            this.isDingQueing = false;
            this.seats = null;
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.EXIT_NOTIFY_PUSH, (data) => {
            const userId = data;
            const s = this.getSeatByID(userId);
            if(s != null){
                s.userId = 0;
                s.name = '';
                this.dispatchEvent(cc.vv.game_event_map.USER_STATE_CHANGED, s);
            }
        });


        cc.vv.net.addHandler(cc.vv.game_event_map.DISPRESS_PUSH, (data) => {
            this.roomId = null;
            this.turn = -1;
            this.dingQue = -1;
            this.isDingQueing = false;
            this.seats = null;
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.DISCONNECT, (data) => {
            if(this.roomId == null){
                cc.vv.wc.show('正在返回游戏大厅');
                cc.director.loadScene('hall');
            }
            else{
                if(this.isOver == false){
                    cc.vv.userMgr.oldRoomId = this.roomId;
                    this.dispatchEvent(cc.vv.game_event_map.DISCONNECT);
                }
                else{
                    this.roomId = null;
                }
            }
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.NEW_USER_COMES_PUSH, (data) => {
            const seatIndex = data.seatIndex;
            let needCheckIp = false;
            if(this.seats[seatIndex].userId > 0){
                this.seats[seatIndex].online = true;
                if(this.seats[seatIndex].ip != data.ip){
                    this.seats[seatIndex].ip = data.ip;
                    needCheckIp = true;
                }
            }
            else{
                data.online = true;
                this.seats[seatIndex] = data;
                needCheckIp = true;
            }

            this.dispatchEvent(cc.vv.game_event_map.NEW_USER, this.seats[seatIndex]);

            if(needCheckIp){
                this.dispatchEvent(cc.vv.game_event_map.CHECK_IP, this.seats[seatIndex]);
            }

        });

        cc.vv.net.addHandler(cc.vv.game_event_map.USER_STATE_PUSH, (data) => {
            const userId = data.userId;
            const seat = this.getSeatByID(userId);
            seat.online = data.online;
            this.dispatchEvent(cc.vv.game_event_map.USER_STATE_CHANGED, seat);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.USER_READY_PUSH, (data) => {
            const userId = data.userId;
            const seat = this.getSeatByID(userId);
            seat.ready = data.ready;
            this.dispatchEvent(cc.vv.game_event_map.USER_STATE_CHANGED, seat);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_HOLDS_PUSH, (data) => {
            const seat = this.seats[this.seatIndex];
            seat.holds = data;

            this.seats.forEach((seat) => {
                !seat.folds     && (seat.folds = []);
                !seat.pengs     && (seat.pengs = []);
                !seat.anGangs   && (seat.anGangs = []);
                !seat.dianGangs && (seat.dianGangs = []);
                !seat.wanGangs  && (seat.wanGangs = []);
                seat.ready = false;
            });
            this.dispatchEvent(cc.vv.game_event_map.GAME_HOLDS);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_BEGIN_PUSH, (data) => {
            this.button = <any>data;
            this.turn = this.button;
            this.gamestate = 'begin';
            this.dispatchEvent(cc.vv.game_event_map.GAME_BEGIN);
        });

        

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_PLAYING_PUSH, () => {
            this.gamestate = 'playing';
            this.dispatchEvent(cc.vv.game_event_map.GAME_PLAYING);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_SYNC_PUSH, (data) => {
            this.numOfMJ = data.numOfMJ;
            this.gamestate = data.state;
            if(this.gamestate == 'dingque'){
                this.isDingQueing = true;
            }
            else if(this.gamestate == 'huanpai'){
                this.isHuanSanZhang = true;
            }
            this.turn = data.turn;
            this.button = data.button;
            this.chuPai = data.chuPai;
            this.huanPaiMethod = data.huanPaiMethod;
            for(let i = 0; i < 4; i++){
                const seat = this.seats[i];
                const sd = data.seats[i];
                seat.holds = sd.holds;
                seat.folds = sd.folds;
                seat.anGangs = sd.anGangs;
                seat.dianGangs = sd.dianGangs;
                seat.wanGangs = sd.wanGangs;
                seat.pengs = sd.pengs;
                seat.dingQue = sd.que;
                seat.hued = sd.hued;
                seat.isZiMo = sd.isZiMo;
                seat.huInfo = sd.huInfo;
                seat.huanPais = sd.huanPais;
                if(i == this.seatIndex){
                    this.dingQue = sd.que;
                }
            }
            this.dispatchEvent(cc.vv.game_event_map.GAME_SYNC);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_DINGQUE_PUSH, (data) => {
            this.isDingQueing = true;
            this.isHuanSanZhang = false;
            this.gamestate = 'dingque';
            this.dispatchEvent(cc.vv.game_event_map.GAME_DINGQUE);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_HUANPAI_PUSH, () => {
            this.isHuanSanZhang = true;
            this.dispatchEvent(cc.vv.game_event_map.GAME_HUANPAI);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.HANGANG_NOTIFY_PUSH, (data) => {
            this.dispatchEvent(cc.vv.game_event_map.HANGANG_NOTIFY, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_ACTION_PUSH, (data) => {
            this.curAction = <any>data;
            this.dispatchEvent(cc.vv.game_event_map.GAME_ACTION, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_CHUPAI_PUSH, (data) => {
            const si = this.getSeatIndexById(data);
            this.doTurnChange(si);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_NUM_PUSH, (data) => {
            this.numOfGames = <any>data;
            this.dispatchEvent(cc.vv.game_event_map.GAME_NUM, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_OVER_PUSH, (data) => {
            const results = data.results;
            this.seats.forEach((seat, i) => {
                seat.score = results.length == 0 ? 0 : results[i].totalScore;
            });
            this.dispatchEvent(cc.vv.game_event_map.GAME_OVER, results);

            if(data.endInfo){
                this.isOver = true;
                this.dispatchEvent(cc.vv.game_event_map.GAME_END, data.endInfo);
            }

            this.reset();
            this.seats.forEach((seat) => {
                this.dispatchEvent(cc.vv.game_event_map.USER_STATE_CHANGED, seat);
            });
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.MJ_COUNT_PUSH, (data) => {
            this.numOfMJ = <any>data;
            this.dispatchEvent(cc.vv.game_event_map.MJ_COUNT, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.HU_PUSH, (data) => {
            this.doHu(data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_CHUPAI_NOTIFY_PUSH, (data) => {
            const userId = data.userId;
            const pai = data.pai;
            const si = this.getSeatIndexById(userId);
            this.doChupai(si, pai);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_MOPAI_PUSH, (data) => {
            this.doMopai(this.seatIndex, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GUO_NOTIFY_PUSH, (data) => {
            const userId = data.userId;
            const pai = data.pai;
            const si = this.getSeatIndexById(userId);
            this.doGuo(si, pai);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GUO_RESULT, (data) => {
            this.dispatchEvent(cc.vv.game_event_map.GUO_RESULT);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GUOHU_PUSH, (data) => {
            this.dispatchEvent(cc.vv.game_event_map.PUSH_NOTICE, {
                info:'过胡',
                time: 1.5
            });
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.HUANPAI_NOTIFY, (data) => {
            const seat = this.getSeatByID(data.si);
            seat.huanPais = data.huanPais;
            this.dispatchEvent(cc.vv.game_event_map.HUANPAI_NOTIFY, seat);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_HUANPAI_OVER_PUSH, (data) => {
            let info = '';
            const method = data.method;
            switch(method){
                case 0:
                    info = '换对家牌';
                    break;
                case 1:
                    info = '换下家牌';
                    break;
                default:
                    info = '换上家牌';
                    break;
            }
            this.huanPaiMethod = method;
            cc.vv.gameNetMgr.isHuanSanZhang = false;
            this.dispatchEvent(cc.vv.game_event_map.GAME_HUANPAI_OVER);
            this.dispatchEvent(cc.vv.game_event_map.PUSH_NOTICE, {
                info,
                time: 2,
            });
        });


        cc.vv.net.addHandler(cc.vv.game_event_map.PENG_NOTIFY_PUSH, (data) => {
            const userId = data.userId;
            const pai = data.pai;
            const si = this.getSeatIndexById(userId);
            this.doPeng(si, pai);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GANG_NOTIFY_PUSH, (data) => {
            const userId = data.userId;
            const pai = data.pai;
            const si = this.getSeatIndexById(userId);
            this.doGang(si, pai, data.gangType);
        });


        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_DINGQUE_NOTIFY_PUSH, (data) => {
            this.dispatchEvent(cc.vv.game_event_map.GAME_DINGQUE_NOTIFY, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.GAME_DINGQUE_FINISH_PUSH, (data) => {
            for(let i = 0, l = (<any>data).length; i < l; i++){
                this.seats[i].dingQue = data[i];
                if(i == this.seatIndex){
                    this.dingQue = data[i];
                }
            }
            this.dispatchEvent(cc.vv.game_event_map.GAME_DINGQUE_FINISH, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.CHAT_PUSH, (data) => {
            this.dispatchEvent(cc.vv.game_event_map.CHAT_PUSH, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.QUICK_CHAT_PUSH, (data) => {
            this.dispatchEvent(cc.vv.game_event_map.QUICK_CHAT_PUSH, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.EMOJI_PUSH, (data) => {
            this.dispatchEvent(cc.vv.game_event_map.EMOJI_PUSH, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.DISSOLVE_NOTICE_PUSH, (data) => {
            this.dissolveData = data;
            this.dispatchEvent(cc.vv.game_event_map.DISSOLVE_NOTICE, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.DISSOLVE_CANCEL_PUSH, (data) => {
            this.dissolveData = data;
            this.dispatchEvent(cc.vv.game_event_map.DISSOLVE_CANCEL, data);
        });

        cc.vv.net.addHandler(cc.vv.game_event_map.VOICE_MSG_PUSH, (data) => {
            this.dispatchEvent(cc.vv.game_event_map.VOICE_MSG, data);
        });
    }

    /**根据用户ID获取座位编号 */
    getSeatIndexById(userId){
        for(let i = 0; i < this.seats.length; i++){
            let s = this.seats[i];
            if(s.userId == userId){
                return i;
            }
        }
        return -1;
    }

    /**向mjgame的场景的canvas发送事件 */
    dispatchEvent(event: cc.game_event_map[keyof cc.game_event_map], data?){
        if(this.dataEventHandler){
            this.dataEventHandler.emit(event, data);
        }
        else{
            // 解决最后一个玩家进入导致的还没初始化完脚本就执行发送事件的BUG（会导致有些事件收不到）
            setTimeout(() => {
                this.dispatchEvent(event, data);
            }, 500);
        }
    }

    /**连接游戏服务器 */
    connectGameServer(data: cc.ret){
        this.dissolveData = null;
        cc.vv.net.ip = data.ip + ':' + data.port;
        console.log('%c开始连接游戏服务器， 地址是：' + data.ip + ':' + data.port, cc.vv.logStyle);
        
        const onConnectOK = () => {
            console.log('%c连接游戏服务器成功', cc.vv.logStyle);
            const sd = <cc.ret>{
                token: data.token,
                roomId: data.roomId,
                time: data.time,
                sign: data.sign,
            };
            cc.vv.alert.show('连接服务器成功',sd.toString());
            cc.vv.net.send(cc.vv.game_event_map.LOGIN, sd);
        };
        
        const onConnectFailed = () => {
            console.log('%c连接游戏服务器失败', cc.vv.logStyle);
            cc.vv.alert.show('连接服务器失败','');
            cc.vv.wc.hide();
        };

        cc.vv.wc.show('正在进入房间');
        cc.vv.net.connect(onConnectOK, onConnectFailed);
    }


    /**初始化牌的状态的各种信息 */
    prepareReplay(roomInfo: cc.history, detailOfGame: cc.roomInfo){
        this.roomId = roomInfo.id;
        this.seats = roomInfo.seats;
        this.turn = detailOfGame.base_info.button;
        const baseInfo = detailOfGame.base_info;
        this.seats.map((seat, i) => {
            seat.seatIndex = i;
            seat.score = null;
            seat.holds = baseInfo.game_seats[i];
            seat.pengs = [];
            seat.anGangs = [];
            seat.wanGangs = [];
            seat.dianGangs = [];
            seat.folds = [];
            if(cc.vv.userMgr.userId == seat.userId){
                this.seatIndex = i;
            }
        });

        this.conf = {
            type: baseInfo.type,
        };
        if(this.conf.type == null){
            this.conf.type = 'xzdd';
        }
    }



    /** 返回玩法的字符串 */
    getWanfa(){
        const conf = this.conf;
        if(conf && conf.maxGames != null && conf.maxFan != null){
            let strArr = [];
            strArr.push(conf.maxGames + '局');
            strArr.push(conf.maxFan + '番封顶');
            if(conf.hsz){
                strArr.push('换三张')
            }
            if(conf.zimo){
                strArr.push('自摸加番')
            }
            else{
                strArr.push('自摸加底');
            }
            if(conf.jiangdui){
                strArr.push('将对')
            }
            if(conf.dianganghua == 1){
                strArr.push('点杠花(自摸)')
            }
            else{
                strArr.push('点杠花(放炮)')                
            }
            if(conf.menqing){
                strArr.push('门清、中张');
            }
            if(conf.tiandihu){
                strArr.push('天地胡');
            }
            return strArr.join(' ');
        }
        return '';
    }

    /**获取所有牌的数据 */
    getSelfData(){
        return this.seats[this.seatIndex];
    }


    /**根据回合获取当前该谁在出牌 （0,1,2,3） */
    getLocalIndex(index: number){
        let ret = (index - this.seatIndex + 4) % 4;
        return < 0 | 1 | 2 | 3>ret;
    }


    /**根据用户ID获取用户详细信息 */
    getSeatByID(userId){
        const seatIndex = this.getSeatIndexById(userId);
        const seat = this.seats[seatIndex];
        return seat;
    }


    /**是不是自己 */
    isOwner(){
        return this.seatIndex == 0;
    }

    /**执行过牌操作 */
    doGuo(seatIndex: number, pai){
        const seatData = this.seats[seatIndex];
        const folds = seatData.folds;
        folds.push(pai);
        this.dispatchEvent(cc.vv.game_event_map.GUO_NOTIFY, seatData);
    }

    /**
     * 执行出牌操作
     * @param seatIndex 
     * @param pai 
     */
    doChupai(seatIndex: number, pai){
        const seatData = this.seats[seatIndex];
        this.chuPai = pai;
        console.log(`出牌前${seatData.userId}的牌是：${cc.vv.debugToTextArr(seatData.holds)}`);
        if(seatData.holds){
            const idx = (seatData.holds as any[]).indexOf(pai);
            (seatData.holds as any[]).splice(idx, 1);  
            console.log(`出牌后${seatData.userId}的牌是：${cc.vv.debugToTextArr(seatData.holds)}`);
        }
        this.dispatchEvent(cc.vv.game_event_map.GAME_CHUPAI_NOTIFY, {seatData, pai});
    }

    /**
     * 执行摸牌操作
     * @param seatIndex 
     * @param pai 
     */
    doMopai(seatIndex: number, pai){
        const seatData = this.seats[seatIndex];
        if(seatData.holds){
            (<any[]>seatData.holds).push(pai);
            this.dispatchEvent(cc.vv.game_event_map.GAME_MOPAI, {seatIndex, pai});
        }
    }


    /**
     * 执行回合改变的操作
     * @param si 
     */
    doTurnChange(si){
        const data = {
            last: this.turn,
            turn: si,
        };
        this.turn = si;
        this.dispatchEvent(cc.vv.game_event_map.GAME_CHUPAI, data);
    }

    /**
     * 执行碰牌操作
     * @param seatIndex 
     * @param pai 
     */
    doPeng(seatIndex: number, pai){
        const seatData = this.seats[seatIndex];
        // 移除手牌
        if(seatData.holds){
            for(let i = 0; i < 2; i++){
                if(Array.isArray(seatData.holds)){
                    const idx = seatData.holds.indexOf(pai);
                    seatData.holds.splice(idx, 1);
                }
            }
        }

        // 更新碰牌数据
        const pengs = seatData.pengs;
        pengs.push(pai);
        this.dispatchEvent(cc.vv.game_event_map.PENG_NOTIFY, seatData);
    }

    /**
     * 返回杠牌的类型('angang' | 'diangang' | 'wangang')
     * @param seatData 
     * @param pai 
     * @return 'angang' | 'diangang' | 'wangang'
     */
    getGangType(seatData: cc.seat, pai): cc.gangType{
        if(seatData.pengs.indexOf(pai) != -1){
            return 'wangang';
        }
        else{
            let cnt = 0;
            for(let i = 0; i < (seatData.holds as any[]).length; i++){
                if(seatData.holds[i] == pai){
                    cnt++;
                }
            }

            if(cnt == 3){
                return 'diangang';
            }
            else{
                return 'angang';
            }
        }
    }


    /**
     * 执行杠牌操作
     * @param seatIndex 
     * @param pai 
     * @param gangtype 
     */
    doGang(seatIndex: number, pai, gangtype?: cc.gangType){
        const seatData = this.seats[seatIndex];

        if(!gangtype){
            gangtype = this.getGangType(seatData, pai);
        }

        
        if(gangtype == 'wangang'){
            if(seatData.pengs.indexOf(pai) != -1){
                const idx = seatData.pengs.indexOf(pai);
                (seatData.pengs as any[]).splice(idx, 1);
            }
        }
        else if(gangtype == 'angang'){
            seatData.anGangs.push(pai);
        }
        else if(gangtype == 'diangang'){
            seatData.dianGangs.push(pai);
        }

        if(seatData.holds){
            for(let i = 0; i <= 4; i++){
                const idx = (seatData.holds as any[]).indexOf(pai);
                if(idx == -1){
                    // 如果没有找到，标识移除完了，直接跳出循环
                    break;
                }
                (seatData.holds as any[]).splice(idx, 1);
            }
        }

        this.dispatchEvent(cc.vv.game_event_map.GANG_NOTIFY, {seatData, gangtype});
    }


    /**
     * 执行胡牌操作
     * @param data 
     */
    doHu(data){
        this.dispatchEvent(cc.vv.game_event_map.HUPAI, data);
    }


    /**重置数据 */
    reset(){
        this.turn = -1;
        this.chuPai = -1;
        this.dingQue = -1;
        this.button = -1;
        this.gamestate = '';
        this.isDingQueing = false;
        this.isHuanSanZhang = false;
        this.curAction = null;
        this.seats.forEach((seat) => {
            seat.holds = [];
            seat.folds = [];
            seat.pengs = [];
            seat.anGangs = [];
            seat.dianGangs = [];
            seat.wanGangs = [];
            seat.dingQue = [];
            seat.ready = false;
            seat.hued = false;
            seat.huanPais = null;
            this.huanPaiMethod = -1;
        });
    }
    

    /**清空数据 */
    clear(){
        this.dataEventHandler = null;
        if(this.isOver == null){
            this.seats = null;
            this.roomId = null;
            this.maxNumOfGames = 0;
            this.numOfGames = 0;
        }
    }
}


